/*
 * AIHandle.h
 *
 *  Created on: Nov 3, 2008
 *      Author: Ryan
 */

#ifndef AIHANDLE_H_
#define AIHANDLE_H_

#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>

#include "../AIInterface.h"
#include "../Objects/Player.h"

//TODO: Remove this debug include
#include "../Objects/Logger.h"

namespace OOInterface
{

class AIHandle
{
public:
	AIHandle( AIInterface* i ) : _initialized(false), _i( i ) { _i->attachAI( this ); }
	virtual ~AIHandle() {};

	/**
	 * initialize( ... ):
	 * Uses the Template Method pattern to ensure that run() will be available to run after
	 * the abstract method init( ... ) has been called. Initialize is required to be called
	 * by an AIInterfaceImpl during the initialization process to allow the AI to init and
	 * run.
	 *
	 * @param self The object representing this AI as a player in the game.
	 */
	void initialize( ConstPlayerPtr self )
	{
		boost::mutex::scoped_lock lock(_mutex);
		_initialized = true;

		init( self );

		_initCondition.notify_one();
	}

	/**
	 * runThread() :
	 * Enforces that initialize must be called before an AI is allowed to go into its
	 * main run loop. Utilizes the Template Method Pattern( GoF p.
	 */
	void runThread()
	{
		boost::mutex::scoped_lock lock(_mutex);
		while( !_initialized )
			_initCondition.wait( lock );

		try {
			run();
		}
		catch( ... )
		{
			OOInterface::Logger::getInstance("AI.txt") << "AI threw an exception, exiting from run()" << std::endl;
		}
	}

protected:
	/**
	 * getAIInterface():
	 * Returns the pointer to the AIInterface that this AI is using as its
	 * interface to the game.
	 *
	 * @return The AIInterface.
	 */
	inline AIInterface* getAIInterface() const { return _i; }

	/**
	 * run()
	 *
	 * This is the function that will be called when the AI is spawned into its own thread.
	 * The bulk of the AI's "thinking" should be done in this portion as not to bog down
	 * the game.
	 */
	virtual void run() = 0;

	/**
	 * init( ... ):
	 * Allows the AI to initialize itself during the beginning of the game. This will be
	 * called by the AIInterface during its initialization process sometime after the
	 * state is considered to be stable for the AI to be able to interact with it.
	 *
	 * Guarantees: After init has completed, the AI is free to start its main run loop.
	 *
	 * @param self The object representing this AI as a player in the game.
	 */
	virtual void init( ConstPlayerPtr self ) = 0;

private:
	boost::mutex _mutex;
	boost::condition _initCondition;
	bool _initialized;

	AIInterface* _i;

	// Forbid copying of AIHandles
	AIHandle( const AIHandle& a ) {}
	AIHandle& operator=( const AIHandle& a ) { return *this; }
};

}

#endif /* AIHANDLE_H_ */
